import json, time, os
from datetime import datetime, timedelta
from multiprocessing.dummy import Pool
from PyQt5.QtCore import QThread, pyqtSignal, QMutex
from PyQt5.QtSql import QSqlDatabase, QSqlQuery

from utils.spiders import AcquireInfoTotal, DataResolver
from utils.tools import generate_rdm_name, shift_report, read_json
from requests import exceptions, ConnectTimeout
from utils.newspider import lis_new

def patient_info(pid, query_list=None, start_date_given=None, end_date_given=None):
    result={}
    
    if start_date_given:
        start_date = start_date_given
        if end_date_given not in [None, "None", "无信息", ""]:
            end_date = datetime.strptime(end_date_given, "%Y.%m.%d")
            end_date = datetime.strftime(end_date, "%Y-%m-%d") 
            
        else:
            end_date = time.strftime("%Y-%m-%d",  time.localtime())
            
    else:
        start_date = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=-30)
        start_date = datetime.strftime(start_date, "%Y-%m-%d") 
        end_date = time.strftime("%Y-%m-%d",  time.localtime())

    try:
        new_lis = lis_new(pid, start_date, end_date)
    except Exception as e:
        result['住院号'] = pid
        result['姓名']= "暂无信息"
    result['化验单'] = new_lis.get('lis')
    result['住院号'] = new_lis.get('patno')
    result['姓名'] = new_lis.get('patname')
    result['年龄'] = new_lis.get('pat_agestr')
    result['性别'] = new_lis.get('pat_sex')
    val = new_lis.get('req_bedno')
    if val.isnumeric():
        ward_bed = read_json("ward_bed.json")
        for each in ward_bed:
            
            if str(int(val)) in each['bed']:
                val = str(int(each['ward'])*100+int(val))
                val = str(val).rjust(4, "0")
                break
    result['床号'] = val
    result['身份证明号'] = new_lis.get('pat_idcardno')

    return result

def patient_info_mult(pid, query_list=None):
    if query_list is None:
        query_list = ['病程记录', 'LIS报告单', 'PACS报告单', ]
    query_app = AcquireInfoTotal(pid)
    query_dic = {}

    for each in query_list:
        result = query_app.query_content(query_kind=each)   
        query_dic.update(result)

    data_resolved = DataResolver(query_app.pid)
    data_resolved.record_resolve(query_dic)
    result = data_resolved.patient_info
    if result:
        return result
    else:
        raise Exception(f"爬虫网络无【{pid}】记录！")
# 访问数据库要的线程锁
locker = QMutex()

class FreshInfoThread(QThread):
    # 用来延迟刷新中医会诊功能中病史的线程
    success = pyqtSignal(int)
   

    def __init__(self, window, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.window = window


    def run(self):
        while not self.window:
            self.sleep(1)
        self.success.emit(1)

class RunDipTh(QThread):
   

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
       

    def run(self):
        os.system('pythonw.exe .\\dip\\main_win_dip.py')



class DelThread(QThread):
    success = pyqtSignal(str)
    error = pyqtSignal(str)

    def __init__(self, pid, row, del_flag, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.pid = pid
        self.row = row
        self.del_flag = del_flag


    def run(self):

        try:

        

            con = QSqlDatabase.addDatabase('QSQLITE', generate_rdm_name(6))

            con.setDatabaseName('.\\DB\\data.db')

            if not con.open():
                # 不加这句会出现QSqlQuery::exec: database not open错误
                return

            query = QSqlQuery(con)

            sql = f"""
                UPDATE patients
                SET del_flag={self.del_flag}
                WHERE 住院号=='{self.pid}'
            """
           
            query.exec(sql)


            con.close()

            # 触发信号

            self.success.emit("成功")

        except ConnectTimeout or exceptions.ConnectTimeout:
            self.error.emit("爬虫网络连接超时！")



        except Exception as e:
            
            self.error.emit(f"出错：{e}")
class RenewThread(QThread):
    success = pyqtSignal(int, dict,)
    error = pyqtSignal(str)

    def __init__(self, pid, row,  start_date_given, end_date_given,*args, **kwargs,):
        super().__init__(*args, **kwargs)
        self.pid = pid
        self.row = row
        self.start_date_given = start_date_given
        self.end_date_given = end_date_given


    def run(self):

        try:
            final_result={}
            with open('.\\DB\\key_words.json', 'r', encoding="utf8") as fk:
                keywords = json.load(fk)

            con = QSqlDatabase.addDatabase('QSQLITE', generate_rdm_name(6))

            con.setDatabaseName('.\\DB\\data.db')

            if not con.open():
                # 不加这句会出现QSqlQuery::exec: database not open错误
                return

            query = QSqlQuery(con)

            result = patient_info(self.pid, start_date_given=self.start_date_given, end_date_given=self.end_date_given)
            
                
            # result = {k:v for k,v in result.items() if v not in ["", None, "None", "无信息"]}
            result = {k:v for k,v in result.items() if k in ["化验单", "身份证明号"]}
            
            sql = f'select info_dict from patients where 住院号=="{self.pid}"'

            query = QSqlQuery(con)
            query.exec(sql)
            if query.first():
                old_dict = query.value(0)

                old_dict = json.loads(old_dict)
                old_dict.update(result)

                final_result = old_dict
            else:
                final_result = result
            a = []
            for k, v in final_result.items():
                if k in keywords:
                    a.append(f"{k}='{v}'")
            a.append(f"info_dict='{json.dumps(final_result, ensure_ascii=False)}'")
            

            data_to_update = ', '.join(a)
            sql = f"""
                UPDATE patients
                SET {data_to_update}
                WHERE 住院号=={self.pid}
            """
            # 读写数据库前上锁
           
            # locker.lock()
            query.exec(sql)
            # 读写数据库结束后解锁
            # locker.unlock()

            con.close()

            # 触发信号

            self.success.emit(self.row, final_result,)

        except ConnectTimeout or exceptions.ConnectTimeout:
            self.error.emit("爬虫网络连接超时！")



        except Exception as e:
            
            self.error.emit(f"出错：{e}")

class UpdateThread(QThread):
    success = pyqtSignal(dict)
    error = pyqtSignal(str)

    def __init__(self, pid, info_dic, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.pid = pid
        self.info_dic = info_dic


    def run(self):

        try:

            with open('.\\DB\\key_words.json', 'r', encoding="utf8") as fk:
                keywords = json.load(fk)

            con = QSqlDatabase.addDatabase('QSQLITE', generate_rdm_name(6))

            con.setDatabaseName('.\\DB\\data.db')

            if not con.open():
                # 不加这句会出现QSqlQuery::exec: database not open错误
                return

            query = QSqlQuery(con)

            result = self.info_dic
            a = []
            for k, v in result.items():
                if k in keywords:
                    a.append(f"{k}='{v}'")
            a.append(f"info_dict='{json.dumps(result, ensure_ascii=False)}'")
            

            data_to_update = ', '.join(a)
            sql = f"""
                UPDATE patients
                SET {data_to_update}
                WHERE 住院号=={self.pid}
            """
            # 读写数据库前上锁
           
            # locker.lock()
            query.exec(sql)
            # 读写数据库结束后解锁
            # locker.unlock()

            con.close()

            # 触发信号

            self.success.emit(self.info_dic)

        except ConnectTimeout or exceptions.ConnectTimeout:
            self.error.emit("爬虫网络连接超时！")



        except Exception as e:
            
            self.error.emit(f"出错：{e}")

class RefreshAllThread(QThread):
    success = pyqtSignal(int, dict)
    error = pyqtSignal(int, str)
    status = pyqtSignal(int)
    finish = pyqtSignal(int)

    def __init__(self, window, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.window = window
    def run(self):
        
        try:
            
            with open('.\\DB\\key_words.json', 'r', encoding="utf8") as fk:
                keywords = json.load(fk)

            con = QSqlDatabase.addDatabase('QSQLITE', generate_rdm_name(6))

            con.setDatabaseName('.\\DB\\data.db')
            if not con.open():
                raise Exception("数据库未打开")
            query = QSqlQuery(con)

            for idx in range(self.window.table_view.model().rowCount()):
                self.status.emit(idx)
                pid = self.window.table_view.model().index(idx, 1).data()

                result = patient_info(pid, ['病程记录', 'LIS报告单', 'PACS报告单'])
                a = []
                for k, v in result.items():
                    if k in keywords:
                        a.append(f"{k}='{v}'")
                a.append(f"info_dict='{json.dumps(result, ensure_ascii=False)}'")


                data_to_update = ', '.join(a)
                sql = f"""
                    UPDATE patients
                    SET {data_to_update}
                    WHERE 住院号=={pid}
                """
                # 读写数据库前上锁
                # locker.lock()
                query.exec(sql)
                # 读写数据库结束后解锁
                # locker.unlock()

                

                # 触发信号
                self.success.emit(idx, result)
            con.close()
            self.finish.emit(idx)
        except ConnectTimeout or exceptions.ConnectTimeout:

            self.error.emit(idx, "出错：爬虫网络连接超时！")

        except Exception as e:

            self.error.emit(idx, f"出错：{e}",)
        
class RenewAllThread(QThread):
    # TODO:修复全部更新无法爬取“影像学”的bug！！！
    # 获取病人信息的爬虫
    # 信号， 触发信号去更新窗体中的数据
    success = pyqtSignal(int, dict)
    error = pyqtSignal(int, str)

    start_signal = pyqtSignal(int)

    def __init__(self, scheduler, row_index, pid, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.row_index = int(row_index)
       
        self.pid = pid
        self.scheduler = scheduler

    def run(self):
        self.start_signal.emit(self.row_index)
        try:

            with open('.\\DB\\key_words.json', 'r', encoding="utf8") as fk:
                keywords = json.load(fk)

            con = QSqlDatabase.addDatabase('QSQLITE', generate_rdm_name(6))

            con.setDatabaseName('.\\DB\\data.db')
            if not con.open():
                raise Exception("数据库未打开")
            query = QSqlQuery(con)

            

            result = patient_info_mult(self.pid, ['病程记录', 'LIS报告单', 'PACS报告单'])
            a = []
            for k, v in result.items():
                # if self.pid == "23074194":
                #     for k,v in result.items():
                #         print(k,'-', v)
                if k in keywords:
                    a.append(f"{k}='{v}'")
            a.append(f"info_dict='{json.dumps(result, ensure_ascii=False)}'")


            data_to_update = ', '.join(a)
            sql = f"""
                UPDATE patients
                SET {data_to_update}
                WHERE 住院号=={self.pid}
            """
            # 读写数据库前上锁
            # locker.lock()
            query.exec(sql)
            # 读写数据库结束后解锁
            # locker.unlock()

            con.close()

            # 触发信号
            self.success.emit(self.row_index, result)
            self.scheduler.destroy_thread(self)

        except ConnectTimeout or exceptions.ConnectTimeout:

            self.error.emit(self.row_index, "出错：爬虫网络连接超时！")
            self.scheduler.destroy_thread(self)

        except Exception as e:

            self.error.emit(self.row_index, f"出错：{e}",)
            self.scheduler.destroy_thread(self)



class PrintPatientListThread(QThread):
    # 打印病人列表
    # 信号， 触发信号去更新窗体中的数据
    # success = pyqtSignal(str)
    # error = pyqtSignal(str)

    # def __init__(self, xls_path, *args, **kwargs):
    #     super().__init__(*args, **kwargs)
    #     self.xls_path = xls_path


    # def run(self):
    #     try:
    #         file_name = generate_p_list.xls_to_xlsx(self.xls_path)
    #         generate_p_list.p_l_generater(file_name)

    #     except Exception as e:

    #         self.error.emit(f"出错：{e}", )

    pass


class AddUpdateThread(QThread):
    # 获取病人信息的爬虫
    # 信号， 触发信号去更新窗体中的数据
    success = pyqtSignal(dict)
    error = pyqtSignal(str)


    def __init__(self, info_dict, *args, **kwargs):
        super().__init__(*args, **kwargs)
       
        self.info_dict = info_dict

    def run(self):
        pid = self.info_dict.get("住院号")
        if not pid:
            self.error.emit("出错：住院号为空！")
            return
        try:
            result = self.info_dict
            with open('.\\DB\\key_words.json', 'r', encoding="utf8") as fk:
                keywords = json.load(fk)
            keywords.append("info_dict")
            con = QSqlDatabase.addDatabase('QSQLITE', generate_rdm_name(6))

            con.setDatabaseName('.\\DB\\data.db')
            if not con.open():
                return
            query = QSqlQuery(con)
            sql_check = f'select info_dict from patients where 住院号=={pid}'

            query.exec(sql_check)
            if query.first():
                old_dict = query.value(0)
                
                old_dict = json.loads(old_dict)
                old_dict.update(result)
                result = old_dict
                a = []
                for k, v in result.items():
                    if k in keywords:
                        a.append(f"{k}='{v}'")
                a.append(f"info_dict='{json.dumps(result, ensure_ascii=False)}'")
            

                data_to_update = ', '.join(a)
                sql = f"""
                    UPDATE patients
                    SET {data_to_update}
                    WHERE 住院号=={pid}
                """
                query.exec(sql)
            else:
                columns = ', '.join(keywords)
                placeholders = ', '.join('?' * len(keywords))
                sql = 'INSERT INTO patients ({}) VALUES ({})'.format(columns, placeholders)
                # 读写数据库前上锁
                query.prepare(sql)
                for each in keywords:
                    if each == "info_dict":
                        query.addBindValue(json.dumps(result, ensure_ascii=False))
                
                    else:

                        query.addBindValue(str(result.get(each)))

                query.exec()
            # 读写数据库结束后解锁
            # locker.unlock()

            con.close()

            # 触发信号
            self.success.emit(result)
           

        except ConnectTimeout or exceptions.ConnectTimeout:

            self.error.emit("出错：爬虫网络连接超时！")
            

        except Exception as e:

             self.error.emit(f"出错：{e}",)
           

class AddThread(QThread):
    # 获取病人信息的爬虫
    # 信号， 触发信号去更新窗体中的数据
    success = pyqtSignal(dict)
    error = pyqtSignal(str)


    def __init__(self, Adder,  pid, *args, **kwargs):
        super().__init__(*args, **kwargs)
       
        self.pid = pid
        self.Adder = Adder

    def run(self):
        try:
            if not self.pid.isdigit():
                raise Exception(f"住院号【{self.pid}】错误，添加失败！")
            with open('.\\DB\\key_words.json', 'r', encoding="utf8") as fk:
                keywords = json.load(fk)
            keywords.append("info_dict")
            con = QSqlDatabase.addDatabase('QSQLITE', generate_rdm_name(6))

            con.setDatabaseName('.\\DB\\data.db')
            if not con.open():
                return
            query = QSqlQuery(con)
            sql_check = f'select id from patients where 住院号=={self.pid}'

            query.exec(sql_check)
            if query.first():
                self.error.emit(f"出错：{self.pid}已存在",)
                self.Adder.destroy_thread(self)
                con.close()
                return
            

            result = patient_info(self.pid)
            columns = ', '.join(keywords)
            placeholders = ', '.join('?' * len(keywords))
            sql = 'INSERT INTO patients ({}) VALUES ({})'.format(columns, placeholders)
            # 读写数据库前上锁
            query.prepare(sql)
            for each in keywords:
                if each == "info_dict":
                    query.addBindValue(json.dumps(result, ensure_ascii=False))
               
                else:

                    query.addBindValue(str(result.get(each)))

            query.exec()
            # 读写数据库结束后解锁
            # locker.unlock()

            con.close()

            # 触发信号
            self.success.emit(result)
            self.Adder.destroy_thread(self)

        except ConnectTimeout or exceptions.ConnectTimeout:

            self.error.emit("出错：爬虫网络连接超时！")
            self.Adder.destroy_thread(self)

        except Exception as e:

            self.error.emit(f"出错：{e}",)
            self.Adder.destroy_thread(self)


class InfoThread(QThread):

    success = pyqtSignal(dict)
    error = pyqtSignal(int, str, str, str)

    def __init__(self, pid, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.pid = pid

    def run(self):

        con = QSqlDatabase.addDatabase('QSQLITE', generate_rdm_name(6))

        con.setDatabaseName('.\\DB\\data.db')
        if not con.open():
            return

        sql = f'select info_dict from patients where 住院号=={self.pid}'

        query = QSqlQuery(con)
        query.exec(sql)
        if query.first():
            result = query.value(0)
            
            result = json.loads(result)
            # 触发信号
            self.success.emit(result)
        con.close()


class CountThread(QThread):
    success = pyqtSignal(str)
    error = pyqtSignal(int, str, str, str)
    finish = pyqtSignal(int)

    def __init__(self, scheduler, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.scheduler = scheduler

    def run(self):
        flag = 0
        while True:
            # 检测线程数量
            total_count = len(self.scheduler.thread_list)
            # 触发信号 更新页面
            note = f"当前共{total_count}个活动程序"
            self.success.emit(note)
            if total_count == 0:
                flag += 1
            if flag > 10:
                break
            time.sleep(0.5)
        note = "无活动程序"
        self.success.emit(note)
        self.finish.emit(0)

class ShiftThread(QThread):
    success = pyqtSignal(str, str, str)
    status = pyqtSignal(str)
    error = pyqtSignal(str)

    def __init__(self, pid_list, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.pid_list = pid_list
        

    def run(self):
        
        try:
            
            con = QSqlDatabase.addDatabase('QSQLITE', generate_rdm_name(6))

            con.setDatabaseName('.\\DB\\data.db')
            if not con.open():
                return
            pid_list = self.pid_list
            result = {}
            for pid in pid_list:
                try:
                    self.status.emit("正在查询【%s】"%pid)
                    

                    sql = f'select info_dict from patients where 住院号=={pid}'

                    query = QSqlQuery(con)
                    query.exec(sql)
                    if query.first():
                        info_dict = query.value(0)                        
                        info_dict = json.loads(info_dict)             
                    else:
                        result[pid] = {"住院号":""}               
                    result[pid] = info_dict
                except Exception as ec:
                    self.error.emit("%s"%ec)
                    continue
            cur_date, file_kind, random_file_name = shift_report(result)
            self.success.emit(cur_date, file_kind, random_file_name)
            self.status.emit("无活动程序")
            con.close()
        except Exception as e:
            self.error.emit("%s"%e)        
        